//
// Created by feng on 19-3-28.
// PS: Define the heliostat data structure.
//

#ifndef SOLARENERGY_CHIER_HELIOSTAT_CUH
#define SOLARENERGY_CHIER_HELIOSTAT_CUH

#include <cuda_runtime.h>
#include <vector>

enum SubCenterType
{
    Square,
    Poisson
};

namespace solar::cuda
{
    class CudaHeliostat
    {
        public:
            CudaHeliostat()
                : subCenterType_(Square), sub_helio_size_(1), h_local_centers(nullptr),
                  h_local_normals(nullptr)
            {
            }

            /*
            通过聚焦中心和光线来对镜子进行旋转、并计算法向（并不需要实际的旋转，知道法向就可以了）
            */
            virtual void CSetNormalAndRotate(const float3& focus_center, const float3& sunray_dir);

            virtual auto CGetDiscreteMicroHelioOriginsAndNormals_(float3*& d_microhelio_vertexes,
                                                                  float3*& d_microhelio_normals,
                                                                  int id) -> int = 0;

            virtual auto getSubHelioSize() -> int = 0; // 子定日镜的个数

            virtual void setNumberOfSubHelio(int n)
            { // 子定日镜的个数
                sub_helio_size_ = n;
            }

            virtual void CGetSubHeliostatVertexes(std::vector<float3>& SubHeliostatVertexes) = 0;

            virtual void setSurfaceProperty(const std::vector<float>& surface_property,
                                            int focal_input_method) = 0;
            virtual auto getSurfaceProperty() -> std::vector<float> = 0;

            auto generateDeviceMicrohelioGroup(int num_group, int size) -> int*;

            /**
             * Getters and setters of attributes for heliostat object.
             */
            [[nodiscard]] auto getPosition() const -> float3;
            void setPosition(float3 pos_);
            [[nodiscard]] auto getShift() const -> float;
            void setShift(float shift_);

            [[nodiscard]] auto getSize() const -> float3;
            virtual void setSize(float3 size_);
            void setSizeX(float x);
            void setSizeY(float y);
            void setSizeZ(float z);

            [[nodiscard]] float3 getNormal() const;
            void setNormal(float3 normal_);

            void setHelioDepth(float thickness);
            [[nodiscard]] auto getHelioDepth() const -> float;

            void setRefract(float refract);
            [[nodiscard]] auto getRefract() const -> float;

            [[nodiscard]] auto getRowAndColumn() const -> int2;
            void setRowAndColumn(int2 row_col_);

            [[nodiscard]] auto getGap() const -> float2;
            void setGap(float2 gap_);

            [[nodiscard]] auto getSubCenterType() const -> SubCenterType;
            void setSubCenterType(SubCenterType type_);

            [[nodiscard]] auto getPixelLength() const -> float;
            void setPixelLength(float pixel_length_);

            [[nodiscard]] auto getBelongingGridId() const -> int;
            void setBelongingGridId(int belonging_grid_id_);

            auto getCPULocalNormals() -> std::vector<float3>;
            void setCPULocalNormals(float3* h_local_normals_);
            void setCPULocalNormals(std::vector<float3> local_normals);

            auto getCPULocalCenters() -> std::vector<float3>;
            void setCPULocalCenters(float3* h_local_centers_);
            void setCPULocalCenters(std::vector<float3> local_centers);
            [[nodiscard]] auto getHeliostatDepth() const -> float;
            [[nodiscard]] auto getHeliostatrefract() const -> float;
            [[nodiscard]] auto getHeliostatreflect() const -> float;

            double helio_depth_ = 0.003;
            float reflect_{};
            float refract_ = 1.5;
            float3 pos_{};
            float3 size_{};
            float3 vertex_[4]{};
            float3 normal_{};             // 通过函数 CSetNormalAndRotate（）来进行设置
            int2 row_col_{};              // 聚焦型的小定日镜的行数列数？？
            float2 gap_{};                // 聚焦型吗？？？
            SubCenterType subCenterType_; // ——子定日镜的类型？？
            float pixel_length_{};
            int sub_helio_size_; // ——子定日镜的个数
            int belonging_grid_id_{};
            float3* h_local_centers;
            float3* h_local_normals;
            float shift_{}; // ???代表什么
            cudaStream_t stream_ = nullptr;

        private:
            void CSetWorldVertex();
            void CSetNormal(const float3& focus_center, const float3& sunray_dir);
    };
} // namespace solar::cuda

#endif // SOLARENERGY_CHIER_HELIOSTAT_CUH
